package com.gooluke.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.gooluke.aop.DataSourceAnnotationAdvisor;
import com.gooluke.aop.DataSourceAnnotationInterceptor;
import com.gooluke.datasource.DynamicDataSource;
import com.gooluke.datasource.MultiDataSourceProperties;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

/**
 * @author gooluke
 */

@Configuration
@Slf4j
public class DataSourceConfig {

    public static final Map<String, String> dataSources = new HashMap<>();

    @Autowired
    MultiDataSourceProperties dataSourceProperties;

    @Value("${datasource.default:}")
    private String defaultDataSourceName;

    @Bean
    @Primary
    public DynamicDataSource dynamicDataSource() {
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        //存放所有数据源
        Map<Object, Object> targetDataSources = new HashMap<>();
        Map<String, MultiDataSourceProperties.DataSourceConfig> datasourceMap = dataSourceProperties.getDatasource();
        if (datasourceMap.entrySet().size() > 1 && (defaultDataSourceName == null || defaultDataSourceName.isEmpty())) {
            throw new RuntimeException("存在多个数据源，未配置默认数据源：datasource.default");
        }
        datasourceMap.forEach((datasourceName, config) -> {
            DataSource dataSource = createDataSource(config);
            targetDataSources.put(datasourceName, dataSource);
            dataSources.put(datasourceName, datasourceName);
            log.info("已初始化数据库：{}", datasourceName);
            if (datasourceMap.size() == 1 || (defaultDataSourceName != null && !defaultDataSourceName.isEmpty() && defaultDataSourceName.equals(datasourceName))) {
                //这里设置默认数据源
                dynamicDataSource.setDefaultTargetDataSource(dataSource);
                log.info("已设置默认数据源: {}", datasourceName);
            }
        });
        //这里把数据源统一管理
        dynamicDataSource.setTargetDataSources(targetDataSources);
        return dynamicDataSource;
    }

    private DataSource createDataSource(MultiDataSourceProperties.DataSourceConfig dataSourceConfig) {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUrl(dataSourceConfig.getUrl());
        dataSource.setDriverClassName(dataSourceConfig.getDriverClassName());
        dataSource.setUsername(dataSourceConfig.getUsername());
        dataSource.setPassword(dataSourceConfig.getPassword());
        dataSource.setValidationQuery("SELECT 1");
        dataSource.setTestWhileIdle(true);
        dataSource.setTestOnBorrow(false);
        dataSource.setTestOnReturn(false);
        dataSource.setPoolPreparedStatements(true);
        dataSource.setMaxPoolPreparedStatementPerConnectionSize(20);
        return dataSource;
    }

    @Bean
    @Primary
    public SqlSessionFactory sqlSessionFactory(DynamicDataSource dynamicDataSource) throws Exception {
        SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        sessionFactory.setDataSource(dynamicDataSource);
        PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        org.springframework.core.io.Resource[] resources = resolver.getResources("classpath:/mapper/*.xml");
        //org.springframework.core.io.Resource config = resolver.getResource("classpath:mybatis-config.xml");
        sessionFactory.setMapperLocations(resources);
        //sessionFactory.setConfigLocation(config);
        return sessionFactory.getObject();
    }

    @Bean
    @Primary
    public DataSourceTransactionManager transactionManager(DynamicDataSource dynamicDataSource) {
        return new DataSourceTransactionManager(dynamicDataSource);
    }

    /**
     * 采用集成AbstractPointcutAdvisor类，并实现BeanFactoryAware接口的Aop方式的话，需要这里声明@Bean
     */
    //@Bean
    public DataSourceAnnotationAdvisor dataSourceAnnotationAdvisor() {
        DataSourceAnnotationInterceptor dataSourceAnnotationInterceptor = new DataSourceAnnotationInterceptor();
        return new DataSourceAnnotationAdvisor(dataSourceAnnotationInterceptor);
    }

}
